home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 January: Mac OS SDK / Dev.CD Jan 97 SDK2.toast / Development Kits (Disc 2) / OpenDoc / OpenDoc Development / Debugging Support / OpenDoc™ Source Code / Storage / Bento / FSHdr.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1996-08-28  |  21.3 KB  |  732 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        FSHdr.cpp
  3.  
  4.     Contains:    Class definition for ODFSBentoHandlers class.
  5.  
  6.     Owned by:    Vincent Lo
  7.  
  8.     Copyright:    © 1993 - 1996 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     Change History (most recent first):
  11.  
  12.          <6>     8/22/96    EL        1376276: flush after writing label.
  13.          <5>     8/21/96    EL        1376276: change fFileSize only if we are
  14.                                     appending.
  15.          <4>     8/19/96    DH        1376276:OpenDoc corrupts document when out
  16.                                     of disk space creating draft. Made numerous
  17.                                     exceptions fatal container errors. Also
  18.                                     changed calculation of disk space needed
  19.                                     for writes to include size of label.
  20.          <3>     5/24/96    jpa        1246074: Added missing CATCH_ALL's.
  21.          <2>     1/15/96    TJ        Cleaned Up
  22.         <17>     8/12/95    TÇ        1276806 Optimization: use kODFalse instead
  23.                                     of kODTrue in comparisons
  24.         <16>     5/26/95    VL        1251403: Multithreading naming support.
  25.         <15>     5/11/95    EL        Use ODBlockMove instead of memcpy.
  26.         <14>     4/25/95    EL        1242376: Synchronize label between handler
  27.                                     and container after WriteLabel.
  28.         <13>     4/10/95    EL        1236290: No debugger warning of file not
  29.                                     properly closed for DR2.
  30.         <12>      4/7/95    EL        1225905: More ModDate stuff to container.
  31.                                     Use FlipEnd.
  32.         <11>     3/24/95    EL        1225905: Move state information such as mod
  33.                                     date from plfmFile to here
  34.         <10>     3/13/95    EL        1226127 fix bug where endOfWrite is very
  35.                                     close to end of file we need a new block
  36.                                     for the safety label.
  37.          <9>     3/10/95    EL        1223465: allocate buffer on the heap.
  38.                                     1226127 fix bug buffering code destory
  39.                                     safety label at file end. Scan backward for
  40.                                     label if file is corrupted. 1227122
  41.                                     truncate file if space was lost in crash.
  42.          <8>     2/15/95    EL        1213321: Fix buffering bug where part of
  43.                                     the read in data is not the same as data in
  44.                                     a dirty buffer.
  45.          <7>     2/10/95    VL        1205627: Make it work for readonly file.
  46.          <6>     1/31/95    EL        1213321: Buffer the Bento file I/O.
  47.          <5>    11/14/94    VL        1188257: Use Bento errors in BenotDef.h.
  48.          <4>     8/26/94    EL        #1182308 Allows non-byte swapping
  49.                                     format/extract.
  50.          <3>      8/8/94    VL        1170009: Wrong byte calculation in
  51.                                     ReadHandler.
  52.          <2>     6/18/94    MB        Correct memory includes
  53.          <1>     5/27/94    VL        first checked in
  54.  
  55. */
  56.  
  57. #ifndef    _ODTYPES_
  58. #include "ODTypes.h"
  59. #endif
  60.  
  61. #ifndef _FSHDR_
  62. #include "FSHdr.h"
  63. #endif
  64.  
  65. #ifndef _BENTOHDR_
  66. #include "BentoHdr.h"
  67. #endif
  68.  
  69. #ifndef _SESSHDR_
  70. #include "SessHdr.h"
  71. #endif
  72.  
  73. #ifndef _EXCEPT_
  74. #include "Except.h"
  75. #endif
  76.  
  77. #ifndef _FLIPEND_
  78. #include "FlipEnd.h"
  79. #endif
  80.  
  81. #ifndef _PLFMFILE_
  82. #include "PlfmFile.h"
  83. #endif
  84.  
  85. #ifndef __CM_API__
  86. #include "CMAPI.h"
  87. #endif
  88.  
  89. #ifndef _ODMEMORY_
  90. #include "ODMemory.h"
  91. #endif
  92.  
  93. #ifndef _ERRORDEF_
  94. #include "ErrorDef.xh"
  95. #endif
  96.  
  97. #ifndef _BENTODEF_
  98. #include "BentoDef.h"
  99. #endif
  100.  
  101. //==============================================================================
  102. // Constants
  103. //==============================================================================
  104.  
  105. const ODType    kODBentoFileTypeName = "FileCtr";
  106.  
  107. #define kInvalidBuffer 1
  108. /* an invalid value for fBufferBegin */
  109.  
  110. #define MakeHighBitsMask(chunkSize)    ~((chunkSize) - 1)
  111. /* mask for masking off the lower bits */
  112.  
  113. //==============================================================================
  114. // Scalar Types
  115. //==============================================================================
  116.  
  117. //struct ContainerLabelFmt {            /* Layout of a container label:            */
  118. // unsigned char  magicBytes[8];        /* 8 bytes: the magic byte identifier    */
  119. // unsigned short flags;                /* 2    as a short                        */
  120. // unsigned short bufSize;            /* 2    TOC buffer size / 1024            */
  121. // unsigned short majorVersion;        /* 2    major format version number        */
  122. // unsigned short minorVersion;        /* 2    minor format version number        */
  123. // unsigned long    tocOffset;            /* 4    offset to start of TOC            */
  124. // unsigned long    tocSize;            /* 4    total byte size of the TOC        */
  125. //};
  126. //typedef struct ContainerLabelFmt ContainerLabelFmt;
  127.  
  128.  
  129. #pragma segment FSHdr
  130.  
  131. static void ODFlipMove(ODPtr from, ODPtr to, ODULong size)
  132. {
  133.     char    *dest = (char *)to + size - 1;
  134.     char    *src = (char *)from;
  135.     
  136.     while (size--)
  137.         *dest-- = *src++;            
  138. }
  139.  
  140.  
  141. extern void ODBentoFatalError(ODBoolean allowSuppress); // prototype
  142.  
  143. //==============================================================================
  144. // ODFSBentoHandlers
  145. //==============================================================================
  146.  
  147. ODFSBentoHandlers::ODFSBentoHandlers(CMSession session, PlatformFile* file)
  148. {
  149.     fFile = file;
  150.     fSession = session;
  151.     fBuffer = kODNULL;
  152.     fReverseEndian = kODFalse;        /* assume same Endian-ness                */
  153.     
  154.     fChunkSize = 0; // after setting, always calculate fChunkHighBitsMask 
  155.     fChunkHighBitsMask = MakeHighBitsMask(fChunkSize);
  156. }
  157.  
  158. ODFSBentoHandlers::~ODFSBentoHandlers()
  159. {
  160. }
  161.  
  162. void ODFSBentoHandlers::Initialize()
  163. {
  164.     CMSetMetaHandler(fSession, kODBentoFileTypeName, (CMMetaHandler) containerMetahandler);
  165. }
  166.  
  167. CMSession ODFSBentoHandlers::GetCMSession()
  168. {
  169.     return fSession;
  170. }
  171.  
  172. CMRefCon ODFSBentoHandlers::OpenHandler(CMOpenMode mode)
  173. {
  174.     TRY
  175.     
  176.     ODULong    chunkSize;
  177.  
  178.     fFile->Open();
  179.     fFileSize = fFile->GetEndOfFile();
  180.     fPhysicalFileSize = fFileSize;    /* must set it here because used in read label */
  181.     fWriteLimit = fFileSize;        /* normally initialize in read label, but we may not have label */
  182.     fLogicalPos = 0;
  183.     fBufferBegin = kInvalidBuffer; /* buffer not loaded yet */
  184.     fBufferDirty = kODFalse;
  185.     fHasLabel = kODFalse;
  186.     chunkSize = fFile->GetAllocationBlockSize();
  187.     /* make sure it is a multiple of 2 */
  188.     for (fChunkSize = MininumChunkSize; fChunkSize < chunkSize; fChunkSize *= 2)
  189.         ;
  190.         
  191.     fChunkHighBitsMask = MakeHighBitsMask(fChunkSize);
  192.     TRY
  193.         fBuffer = (ODSByte *)ODNewPtr(fChunkSize);
  194.     CATCH_ALL
  195.         /* there may be platform that returns a large chunksize to try to read     */
  196.         /* the whole file into memory. If that fails, we can try to allocate       */
  197.         /* with a default chunksize so that it can still run. In theory even       */
  198.         /* if the default chunksize memory allocation fails, we can still catch    */
  199.         /* and run without buffering, but if memory is really so short at        */
  200.         /* open time, may as well forget about it                                */
  201.         fChunkSize = DefaultChunkSize;
  202.         fChunkHighBitsMask = MakeHighBitsMask(fChunkSize);
  203.         fBuffer = (ODSByte *)ODNewPtr(fChunkSize);    
  204.     ENDTRY
  205.     if ((strcmp(mode, "rb") == 0) || fFile->IsLocked())
  206.         fOpenReadOnly = kODTrue;
  207.     else {
  208.         fOpenReadOnly = kODFalse;
  209.         if (fFileSize > sizeof(ContainerLabelFmt)) {
  210.             CM_UCHAR magicBytes[8];
  211.             CMContainerFlags flags;
  212.             CM_USHORT bufSize;
  213.             CM_USHORT majorVersion;
  214.             CM_USHORT minorVersion;
  215.             ODULong tocOffset;
  216.             ODULong tocSize;
  217.             TRY
  218.                 this->ReadLabelHandler(magicBytes, &flags, &bufSize,
  219.                                          &majorVersion, &minorVersion,
  220.                                          &tocOffset, &tocSize);
  221.             CATCH_ALL
  222.             ENDTRY
  223.         }
  224.     }
  225.     CATCH_ALL
  226.     
  227.     WARN("error %ld error opening file container", (long) ErrorCode());
  228.     ODBentoFatalError(/*allowSuppress*/ kODTrue);
  229.     RERAISE;
  230.     
  231.     ENDTRY
  232.  
  233.     return ((CMRefCon) this);
  234. }
  235.  
  236. void ODFSBentoHandlers::CloseHandler()
  237. {
  238.     TRY
  239.     
  240.     if ( fBufferDirty )
  241.         this->FlushBuffer();
  242.     if ( fBuffer ) {
  243.         ODDisposePtr(fBuffer);
  244.         fBuffer = kODNULL;
  245.     }
  246.     if ( !fOpenReadOnly ) {
  247.         fFile->SetEndOfFile(fFileSize);        /* remove the reserved space */
  248.     }
  249.     fFile->Close();
  250.     fHasLabel = kODFalse;
  251.  
  252.     CATCH_ALL
  253.     
  254.     WARN("error %ld error closing file container", (long) ErrorCode());
  255.     ODBentoFatalError(/*allowSuppress*/ kODTrue);
  256.     RERAISE;
  257.     
  258.     ENDTRY
  259. }
  260.  
  261. CMSize ODFSBentoHandlers::FlushHandler()
  262. {
  263.     int result = 0;
  264.     
  265.     ODVolatile(result);
  266.     
  267.     TRY    
  268.         if (fBufferDirty)
  269.             this->FlushBuffer();
  270.         fFile->FlushVolume();
  271.     CATCH_ALL
  272.         result = -1;
  273.  
  274.         WARN("error %ld error flushing file container", (long) ErrorCode());
  275.         ODBentoFatalError(/*allowSuppress*/ kODTrue);
  276.     ENDTRY
  277.     
  278.     return result;
  279. }
  280.  
  281. CMSize ODFSBentoHandlers::SeekHandler(CM_LONG posOff, CMSeekMode mode)
  282. {
  283.     if (mode == kCMSeekEnd)
  284.         fLogicalPos = fFileSize + posOff;
  285.     else if (mode == kCMSeekCurrent) {
  286.         fLogicalPos = fLogicalPos + posOff;
  287.     }
  288.     else
  289.         fLogicalPos = posOff;
  290.     
  291.     return 0;
  292. }
  293.  
  294. CMSize ODFSBentoHandlers::TellHandler()
  295. {    
  296.     return fLogicalPos;
  297. }
  298.  
  299. CMSize ODFSBentoHandlers::ReadHandler(CMPtr buffer, CMSize elementSize, CMCount theCount)
  300. {
  301.     ODULong    endOfRead, firstReadBlock, lastReadBlock;
  302.  
  303.     ODSLong amountRead = elementSize * theCount; ODVolatile(amountRead);
  304.  
  305.     TRY    
  306.  
  307.     endOfRead = fLogicalPos + amountRead;
  308.     if (endOfRead > fFileSize) {
  309.         amountRead = fFileSize - fLogicalPos;
  310.         endOfRead = fFileSize;
  311.     }
  312.  
  313.     firstReadBlock = fLogicalPos & fChunkHighBitsMask;
  314.     lastReadBlock = (endOfRead-1) & fChunkHighBitsMask;
  315.         
  316.     if (firstReadBlock == lastReadBlock) {
  317.         /* the content to read can be in a single buffer */
  318.         if (firstReadBlock != fBufferBegin) /* the block is not loaded */
  319.             this->ReloadBuffer();
  320.         /* After we make sure the buffer is loaded, we just copy it from the buffer */
  321.         ODBlockMove(fBuffer+fLogicalPos-fBufferBegin, buffer, amountRead);
  322.     }
  323.     else { /* for bigger block we read it directly bypassing the buffer */
  324.         /* if we read directly and part of data is in dirty buffer then write it first */
  325.         if ( fBufferDirty && (firstReadBlock <= fBufferBegin) && (fBufferBegin <= lastReadBlock))
  326.             this->FlushBuffer();
  327.         fFile->SetFilePos(fsFromStart, fLogicalPos);
  328.         fFile->Read((ODSByte*) buffer, &amountRead);
  329.     }
  330.     
  331.     fLogicalPos = endOfRead;
  332.     
  333.     CATCH_ALL
  334.     
  335.     WARN("error %ld error reading file container", (long) ErrorCode());
  336.     ODBentoFatalError(/*allowSuppress*/ kODTrue);
  337.     RERAISE;
  338.     
  339.     ENDTRY
  340.     
  341.     return ((CMSize)amountRead);
  342. }
  343.  
  344. CMSize ODFSBentoHandlers::WriteHandler(CMPtr buffer, CMSize elementSize, CMCount theCount)
  345. {
  346.     ODSLong amountWritten = 0; ODVolatile(amountWritten);
  347.     
  348.     TRY
  349.     
  350.     if (theCount > 0) {    
  351.     
  352.         amountWritten = elementSize * theCount;
  353.         
  354.         // endOfWrite is the end of space for the write we must perform:
  355.         ODULong endOfWrite = fLogicalPos + amountWritten;
  356.         
  357.         // endOfNeed is the amount of total space we need, which includes the
  358.         // size of the label which must be included at end of file.  We must
  359.         // use this value to calculate the new end of file whenever the file
  360.         // must be made longer:
  361.         ODULong endOfNeed = endOfWrite;
  362.         if ( fHasLabel ) // we only need a label if we already have a label
  363.             endOfNeed += sizeof(ContainerLabelFmt);
  364.         
  365.         ODULong beginWriteBlock = fLogicalPos & fChunkHighBitsMask;
  366.         ODBoolean needToWrite = kODTrue;
  367.  
  368.         if ((beginWriteBlock == ((endOfWrite-1) & fChunkHighBitsMask)) && (beginWriteBlock != fBufferBegin)) {
  369.             /* changes are all in a single buffer but data not loaded, load it now */
  370.             this->ReloadBuffer();
  371.         }
  372.  
  373.         if (fBufferBegin != kInvalidBuffer) { /* we have a buffer */
  374.             if (fLogicalPos < fBufferBegin) { /* the tail of the write may touch the buffer */
  375.                 if (endOfWrite > fBufferBegin) { /* yes, the tail touches the buffer */
  376.                     /*
  377.                         fLogicalPos     fBufferBegin      endOfWrite
  378.                              |              |                 |       |
  379.                                             <-       ChunkSize      ->
  380.                                             <-  toMove      ->
  381.                     */
  382.                     ODULong toMove = endOfWrite - fBufferBegin;  /* move so many bytes into the buffer */
  383.                     if (toMove > fChunkSize)             /* but no larger than the buffer itself */
  384.                         toMove = fChunkSize;
  385.                     /* update the part of the buffer that has been changed */
  386.                     ODBlockMove((char *)buffer+fBufferBegin-fLogicalPos, fBuffer, toMove);
  387.                     /* note that we do not need to dirty it because we still write it out */
  388.                 }
  389.             }
  390.             else { /* the front part of the write may touch the buffer */
  391.                 ODULong theGap = fLogicalPos - fBufferBegin;
  392.                 if (theGap < fChunkSize) { /* yes, it does touch the buffer */
  393.                     /*
  394.                         fBufferBegin    fLogicalPos            endOfWrite
  395.                              |               |        |            |
  396.                              <-       ChunkSize      ->
  397.                              <-   theGap    ->
  398.                                              <-   amountWritten   ->
  399.                                              <-toMove->
  400.  
  401.                     */
  402.                     ODULong toMove = amountWritten;
  403.                     if (toMove + theGap > fChunkSize)
  404.                         toMove = fChunkSize - theGap;
  405.                     else {
  406.                         fBufferDirty = kODTrue; /* dirty it so we would write it out later */
  407.                         needToWrite = kODFalse;    /* for now, no writing is necessary */
  408.                     }
  409.                     ODBlockMove(buffer, fBuffer + theGap, toMove); /* update the buffer */
  410.                 }
  411.             }
  412.         }
  413.          
  414.         if (endOfNeed > fFileSize) { /* we don't have enough room */
  415.             if (endOfNeed > fWriteLimit) {
  416.                 /* extend it to block boundry */
  417.                 ODULong newEndOfFile = ((endOfNeed + fChunkSize)) & fChunkHighBitsMask;
  418.  
  419.                 ODSLong    newWriteLimit = newEndOfFile;
  420.                 if ( fHasLabel ) {
  421.                     newWriteLimit = newEndOfFile - sizeof(ContainerLabelFmt);
  422.                 }
  423.                 /* We will add at least another block to file, so we need a new label at end */
  424.                 fFile->SetEndOfFile(newEndOfFile);
  425.                 fPhysicalFileSize = newEndOfFile;
  426.                 fWriteLimit = newWriteLimit;
  427.                 if ( fHasLabel ) {
  428.                     if ((fWriteLimit & fChunkHighBitsMask) == fBufferBegin) {
  429.                         /* the label at the end will overlap with the buffer, put it in the buffer */
  430.                         ODBlockMove(&fLabel, fBuffer + fChunkSize - sizeof(ContainerLabelFmt), sizeof(ContainerLabelFmt));
  431.                     }
  432.                     fFile->SetFilePos(fsFromStart, fWriteLimit);
  433.                     TRY
  434.                         ODSLong labelSize = sizeof(ContainerLabelFmt);
  435.                         fFile->Write((const ODSByte*)&fLabel, &labelSize);
  436.                         /* if fails, no safety label at end of end, that is not end of the world */
  437.                         fFile->FlushVolume();
  438.                     CATCH_ALL
  439.                     ENDTRY
  440.                 }
  441.             }
  442.             if (endOfWrite > fFileSize) /* we are appending */
  443.                 fFileSize = endOfWrite;
  444.         }
  445.         if ( needToWrite ) {
  446.             fFile->SetFilePos(fsFromStart, fLogicalPos);
  447.             fFile->Write((const ODSByte*)buffer, &amountWritten);
  448.         }
  449.         fLogicalPos = endOfWrite;
  450.     }
  451.     CATCH_ALL
  452.     
  453.     WARN("error %ld error writing file container", (long) ErrorCode());
  454.     ODBentoFatalError(/*allowSuppress*/ kODTrue);
  455.     RERAISE;
  456.     
  457.     ENDTRY
  458.  
  459.     return ((CMSize)amountWritten);
  460. }
  461.  
  462. void ODFSBentoHandlers::FlushBuffer()
  463. {
  464.     ODSLong        theSize = fChunkSize;    
  465.  
  466.     fFile->SetFilePos(fsFromStart, fBufferBegin);
  467.     if (fPhysicalFileSize - fBufferBegin < fChunkSize)
  468.         theSize = fPhysicalFileSize - fBufferBegin;
  469.     fFile->Write(fBuffer, &theSize);
  470.     fBufferDirty = kODFalse;
  471. }
  472.  
  473. void ODFSBentoHandlers::ReloadBuffer()
  474. {
  475.     ODSLong        theSize;    
  476.  
  477.     if ( fBufferDirty )
  478.         this->FlushBuffer();
  479.     fBufferBegin = fLogicalPos & fChunkHighBitsMask;
  480.     fFile->SetFilePos(fsFromStart, fBufferBegin);
  481.     theSize = fChunkSize;
  482.     if (fPhysicalFileSize - fBufferBegin < fChunkSize)
  483.         theSize = fPhysicalFileSize - fBufferBegin;
  484.     fFile->Read(fBuffer, &theSize);
  485. }
  486.  
  487. CMEofStatus ODFSBentoHandlers::EOFHandler()
  488. {
  489.     return ((CMEofStatus) kODFalse);
  490.  
  491. }
  492.  
  493. CMBoolean ODFSBentoHandlers::TruncHandler(CMSize containerSize)
  494. {
  495.     fFileSize = containerSize;        
  496.     return kODTrue;
  497. }
  498.  
  499. CMSize ODFSBentoHandlers::ContainerSizeHandler()
  500. {
  501.     return ((CMSize) fFileSize);
  502. }
  503.  
  504. void ODFSBentoHandlers::ReadLabelHandler(CMMagicBytes magicByteSequence,
  505.                                      CMContainerFlags *flags, CM_USHORT *bufSize,
  506.                                      CM_USHORT *majorVersion, CM_USHORT *minorVersion,
  507.                                      CMSize *tocOffset, CMSize *tocSize)
  508. {
  509.     TRY
  510.     
  511.     ODULong        endOfTOC, tempFileEnd;
  512.     char *magicSequence = "\xA4""CM""\xA5""Hdr""\xD7";        /* Must be 8 characters        */
  513.     ODBoolean         labelMatches = fHasLabel;
  514.  
  515.     /* Seek to the end of the label at the end of the container and read it...*/
  516.     
  517.     tempFileEnd = fFileSize;
  518.     while (tempFileEnd > sizeof(ContainerLabelFmt)) {
  519.         fLogicalPos = tempFileEnd - sizeof(ContainerLabelFmt);
  520.         /* if we really want to speed it up, we could compare it directly from the buffer     */
  521.         /* but since we only need to loop through this in corrupted file and that does not    */
  522.         /* occur very often, and even when it happens, the current speed is acceptable          */
  523.         /* so we would leave it as it is now                                                */
  524.         if (this->ReadHandler((CMPtr)&fLabel, (CMSize)sizeof(unsigned char), 8) !=  8)
  525.                 THROW(kODErrBentoErr);
  526.         if (memcmp(&fLabel.magicBytes, magicSequence, 8) == 0)
  527.             labelMatches = kODTrue;
  528.         if (labelMatches) {
  529.             /* Return all the label info... */
  530.             fLogicalPos = tempFileEnd - sizeof(ContainerLabelFmt);
  531.             if (this->ReadHandler((CMPtr)&fLabel, 
  532.                                   (CMSize)sizeof(unsigned char), 
  533.                                   sizeof(ContainerLabelFmt)) !=  sizeof(ContainerLabelFmt))
  534.                     THROW(kODErrBentoErr);
  535.             ODBlockMove(&fLabel.magicBytes, magicByteSequence, 8);
  536. #if kCMDefaultEndian
  537.             /* little endian machine */
  538.             if ((fLabel.flags & kCMLittleEndianTwin) == 0) {
  539. #else
  540.             /* big endian machine */
  541.             if (fLabel.flags & kCMLittleEndianTwin) {
  542. #endif
  543.                 fReverseEndian = kODTrue;
  544.                 *flags = ODFlipShort(fLabel.flags);
  545.                 *bufSize = ODFlipShort(fLabel.bufSize);
  546.                 *majorVersion = ODFlipShort(fLabel.majorVersion);
  547.                 *minorVersion = ODFlipShort(fLabel.minorVersion);
  548.                 *tocOffset = ODFlipLong(fLabel.tocOffset);
  549.                 *tocSize = ODFlipLong(fLabel.tocSize);
  550.             }
  551.             else {
  552.                 fReverseEndian = kODFalse;
  553.                 *flags = (CMContainerFlags)fLabel.flags;
  554.                 *bufSize = (CM_USHORT)fLabel.bufSize;
  555.                 *majorVersion = (CM_USHORT)fLabel.majorVersion;
  556.                 *minorVersion = (CM_USHORT)fLabel.minorVersion;
  557.                 *tocOffset = (CMSize)fLabel.tocOffset;
  558.                 *tocSize = (CMSize)fLabel.tocSize;
  559.             }
  560.             endOfTOC = *tocOffset + *tocSize + sizeof(ContainerLabelFmt);
  561.             if (endOfTOC == tempFileEnd) {
  562.                 /* match exactly, this is most likely to be the label */
  563.                 if (endOfTOC != fFileSize) {
  564. #if ODDebug
  565.                     WARN("The file was corrupted! I will just do my best to read it");
  566. #endif
  567.                     fFileSize = endOfTOC;
  568.                 }
  569.                 fHasLabel = kODTrue;
  570.                 break;
  571.             }
  572.             if (endOfTOC < tempFileEnd) {
  573.                 ContainerLabelFmt tempLabel;
  574.                 fLogicalPos = endOfTOC - sizeof(ContainerLabelFmt);
  575.                 if (this->ReadHandler((CMPtr)&tempLabel, 
  576.                                       (CMSize)sizeof(unsigned char), 
  577.                                       sizeof(ContainerLabelFmt)) !=  sizeof(ContainerLabelFmt))
  578.                     THROW(kODErrBentoErr);
  579.                 if (memcmp(&tempLabel, &fLabel, sizeof(ContainerLabelFmt)) == 0) {
  580. //#if ODDebug
  581. //                    WARN("The file was not closed properly! You get away with it this time");
  582. //#endif
  583.                     /* we passed the sanity check, so we can truncate the file and use the label */
  584.                     fFileSize = endOfTOC;
  585.                     fHasLabel = kODTrue;
  586.                     break;
  587.                 }
  588.                 /* even if we did not pass the test, if the label was at the end, still accept it */
  589.                 if (tempFileEnd == fFileSize) {
  590. #if ODDebug
  591.                     WARN("File looks funny! Send a copy to Bento folks");
  592. #endif
  593.                     fHasLabel = kODTrue;
  594.                     break;
  595.                 }
  596.             }
  597.         } /* it is a label */
  598.         /* otherwise keep scanning backwards */
  599.         labelMatches = kODFalse;
  600.         tempFileEnd -= 1;
  601.     }
  602.     if (fHasLabel) {
  603.         fPhysicalFileSize = fFileSize;
  604.         fWriteLimit = fFileSize;
  605.         if ( !fOpenReadOnly && (fFile->GetEndOfFile() != fFileSize)) {
  606.             fFile->SetEndOfFile(fFileSize);        /* get back the correct size */
  607.         }
  608.     }
  609. #if ODDebug
  610.     else
  611.         WARN("File has no valid Bento label. Cannot be recovered");
  612. #endif
  613.  
  614.     CATCH_ALL
  615.     
  616.     WARN("error %ld error reading file container label", (long) ErrorCode());
  617.     ODBentoFatalError(/*allowSuppress*/ kODTrue);
  618.     RERAISE;
  619.     
  620.     ENDTRY
  621. }
  622.  
  623. void ODFSBentoHandlers::WriteLabelHandler(CMMagicBytes magicByteSequence,
  624.                                         CMContainerFlags flags, CM_USHORT bufSize,
  625.                                         CM_USHORT majorVersion, CM_USHORT minorVersion,
  626.                                         CMSize tocOffset, CMSize tocSize)
  627. {
  628.     TRY
  629.     
  630.     ContainerLabelFmt    theLabel;
  631.         
  632.     /* Fill in the label buffer with the info...                                                                                    */
  633.     
  634.     flags = (CMContainerFlags) ((CM_USHORT)flags & ~kCMLittleEndianTwin);    /* ignore what is passed in */
  635.     if (fReverseEndian) {
  636.         theLabel.flags = ODFlipShort(flags | (kCMLittleEndianTwin & ~kCMDefaultEndian));
  637.         theLabel.bufSize = ODFlipShort(bufSize);
  638.         theLabel.majorVersion = ODFlipShort(majorVersion); 
  639.         theLabel.minorVersion = ODFlipShort(minorVersion);
  640.         theLabel.tocOffset = ODFlipLong(tocOffset);
  641.         theLabel.tocSize = ODFlipLong(tocSize);
  642.     }
  643.     else {
  644.         theLabel.flags = (ODUShort)(flags | kCMDefaultEndian);
  645.         theLabel.bufSize = (ODUShort)bufSize;
  646.         theLabel.majorVersion = (ODUShort)majorVersion; 
  647.         theLabel.minorVersion = (ODUShort)minorVersion;
  648.         theLabel.tocOffset = (ODULong)tocOffset;
  649.         theLabel.tocSize = (ODULong)tocSize;
  650.     }
  651.     
  652.     ODBlockMove(magicByteSequence, theLabel.magicBytes, 8);
  653.  
  654.     /* Write the label to the end of the container value...                                                                */
  655.     
  656.     this->SeekHandler(0, kCMSeekEnd);
  657.     ODSLong labelSize = (unsigned long)this->WriteHandler((CMPtr)&theLabel,
  658.                                             (CMSize)sizeof(unsigned char),
  659.                                             (CMCount)sizeof(ContainerLabelFmt));
  660.     
  661.     if (labelSize != sizeof(ContainerLabelFmt))
  662.         THROW(kODErrBentoErr);
  663.  
  664.     this->FlushHandler();
  665.  
  666.     ODBlockMove(&theLabel, &fLabel, sizeof(ContainerLabelFmt));
  667.     fHasLabel = kODTrue;
  668.     fPhysicalFileSize = fFileSize;
  669.     fWriteLimit = fFileSize;
  670.     fFile->SetEndOfFile(fFileSize);        /* get back the correct size */
  671.  
  672.     CATCH_ALL
  673.     
  674.     WARN("error %ld error writing file container label", (long) ErrorCode());
  675.     ODBentoFatalError(/*allowSuppress*/ kODTrue);
  676.     RERAISE;
  677.     
  678.     ENDTRY
  679. }
  680.  
  681. CMValue ODFSBentoHandlers::ReturnParentValueHandler()
  682. {
  683.     return kODNULL;
  684. }
  685.  
  686. CM_UCHAR* ODFSBentoHandlers::ReturnContainerNameHandler()
  687. {
  688.     static Str63    name;
  689.     
  690.     fFile->GetAsciiName((char*)name,sizeof(name));
  691.     return ((CM_UCHAR *) name);
  692. }
  693.  
  694. CMType ODFSBentoHandlers::ReturnTargetTypeHandler(CMContainer container)
  695. {
  696. ODUnused(container);
  697.  
  698.     return kODNULL;
  699. }
  700.  
  701. void ODFSBentoHandlers::ExtractDataHandler(CMDataBuffer buffer,
  702.                                                  CMSize size, CMPrivateData data)
  703. {
  704.     ODBoolean    reverseEndian = fReverseEndian;
  705.     
  706.     if ((CM_LONG)size < 0) {    /* this means it is endian-ness netural    */
  707.         size = -(CM_LONG)size;
  708.         reverseEndian = kODFalse;
  709.     }
  710.     
  711.     if (reverseEndian)
  712.         ODFlipMove(buffer, data, (size_t)size);
  713.     else
  714.         ODBlockMove(buffer, data, (size_t)size);
  715. }
  716.  
  717. void ODFSBentoHandlers::FormatDataHandler(CMDataBuffer buffer,
  718.                                      CMSize size, CMPrivateData data)
  719. {
  720.     ODBoolean    reverseEndian = fReverseEndian;
  721.     
  722.     if ((CM_LONG)size < 0) {    /* this means it is endian-ness netural    */
  723.         size = -(CM_LONG)size;
  724.         reverseEndian = kODFalse;
  725.     }
  726.     
  727.     if (reverseEndian)
  728.         ODFlipMove(data, buffer, (size_t)size);
  729.     else
  730.         ODBlockMove(data, buffer, (size_t)size);
  731. }
  732.